import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.HashMap;
/**
 * @author weizhuowu
 *
 */
public class ReadThread implements Runnable{

	UDPClient client;

	ReadThread(UDPClient c){
		this.client = c;	
	}

	@Override
	public void run() {

		if(UDPServer.class.equals(client.getClass())){
			System.out.println("Listening on Group: "+client.getLocalIpAddress());
		}else{
			System.out.println("Listening on Group: "+client.getServerAddr());
		}

		while(true){
			String message = null;
			byte[] receiveData = new byte[2048];
			DatagramPacket receivePacket = null;
			try {
				receivePacket = new DatagramPacket(receiveData, receiveData.length);
				client.getUDPSocket().receive(receivePacket);					
			} catch (IOException e) {					
				e.printStackTrace();
			} 	
			message = new String(receivePacket.getData(), 0, receivePacket.getLength());

			if(UDPServer.class.equals(client.getClass())){//LEADER
				if(message.startsWith("IP:")&&message.contains(":PORT:")&&message.contains(":NAME:")){
					/*aliveMsg---update memberList*/
					parseClientInfo(message);					
				}else{
					/*chatMsg---add userName, broadcast*/
					String senderIP = receivePacket.getAddress().getHostAddress();					
					int senderPort = receivePacket.getPort();
					String senderKEY = "IP:"+senderIP+":PORT:"+senderPort;
					String senderUserName = this.client.memberList.get(senderKEY).getUsername();
					String wholeMsg = senderUserName+": "+message;
					((UDPServer)client).broadcastMessage(wholeMsg);
				}

			}else{//CLIENT
				
				if(message.startsWith("IP:") && message.contains(":PORT:")&&message.contains(":NAME:")){
					/*memberListMsg---parse message, refresh local list*/
					this.client.setMemberList(new HashMap<String, UDPNode>());
					String[] memberArray = message.split(";");
					for(int i=0; i< memberArray.length; i++){
						parseClientInfo(memberArray[i]);
					}
					System.out.println("MEMBERLIST----"+client.getMemberList().toString());
				}else if(message.equals("Alive?")){					
                    this.client.updateServerLife();
					/*CheckAliveMsg--respond client's info to leader*/
					this.client.reportAlive();
				}else{
					/*chatMsg---print out*/
					System.out.println(message);
				}
			}		
		}
	}

	/**
	 * Leader get aliveMsg, parse it to get basic user info
	 * Update this user is in leader's memberList(if exists, aliveTry=3;if not, add this new user).
	 * Then operate a memberList check to see whether some node die, update memberList
	 * After, send this new List to all members
	 * @param aliveMsg Message that clients sent to leader to report it's alive.
	 */
	private void parseClientInfo(String aliveMsg){
		AliveMsg msg = new AliveMsg(aliveMsg);
		String userKey = msg.getAliveUserKey();
		String userName = msg.getAliveUserName();
		InetAddress clientIpAddress = msg.getAliveIpAddress();
		int clientPortNum = msg.getAlivePortNum();
		boolean isClientLeader = msg.isAliveLeader();
		HashMap<String, UDPNode> lastestList = new HashMap<String, UDPNode>();

		if(UDPServer.class.equals(this.client.getClass())){//SERVER
			/*Add client, Update and broadcast memberList if list changed*/				
			lastestList.putAll(client.getMemberList());
			lastestList.put(userKey, new UDPNode(userName, clientIpAddress, clientPortNum));	
			if(!lastestList.keySet().equals(client.getMemberList().keySet())){
				((UDPServer)client).broadcastMessage(userName+" joined our group");
				client.setMemberList(lastestList);		
				((UDPServer)client).broadcastMessage(((UDPServer)client).memberListToString());
			}else{
				client.setMemberList(lastestList);
			}			
			
		}else{//CLIENT
			/*Add client into local memberList*/
			this.client.putInMemberList(userKey, new UDPNode(userName,clientIpAddress,clientPortNum,isClientLeader));
		}

	}
	



}
